#include <stdio.h>
#include <stdlib.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/rtnetlink.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#define BUFSIZE 8192
#define ROUTE_PATH "/proc/net/route"

typedef struct route_info
{
   char if_name[32];
   int  dst_ip_addr;
   int  gateway_ip_addr;
   int  flags; //3 default route 1 route
   int  mask;
   int  metric;
   char dst_ip_addr_str[32];
   char gateway_ip_addr_str[32];
   char mask_str[32];
}route_info_t;

static void net_route_gen_ip_str(route_info_t *route_info)
{
    uint8_t *header = (uint8_t *)&route_info->dst_ip_addr;
    snprintf(route_info->dst_ip_addr_str, sizeof(route_info->dst_ip_addr_str), "%d.%d.%d.%d", header[0], header[1], header[2], header[3]);
    header =  (uint8_t *)&route_info->gateway_ip_addr;
    snprintf(route_info->gateway_ip_addr_str, sizeof(route_info->gateway_ip_addr_str), "%d.%d.%d.%d", header[0], header[1], header[2], header[3]);
    header =  (uint8_t *)&route_info->mask;
    snprintf(route_info->mask_str, sizeof(route_info->mask_str), "%d.%d.%d.%d", header[0], header[1], header[2], header[3]); 
}

int net_route_get(char *if_name, route_info_t *route_info)
{
    FILE *fp = fopen("/proc/net/route", "r");
    if(fp == NULL)
    {
       return -1;
    }

    int i = 0;
	char s[20] = {0};
    int useless = 0;

	for (i = 0; i < 11; ++ i)
		fscanf(fp, "%s", s);
   
    while (fscanf(fp, "%s %X %X %d %d %d %d %X %d %d %d", route_info->if_name, &route_info->dst_ip_addr, &route_info->gateway_ip_addr, &useless, &useless, &useless, &route_info->metric, &route_info->mask, &useless, &useless, &useless) != EOF)
	{
        if(strcmp(route_info->if_name, if_name) == 0)
        {
            net_route_gen_ip_str(route_info);
            break;
        }
        else
        {
            memset(route_info, 0, sizeof(route_info_t));
        }
    }

    fclose(fp);
    return 0;     
}

void process_route(struct rtmsg *r, char *buf, int len) {
    struct rtattr *attr;
    int attrlen;

    attr = (struct rtattr *)RTM_RTA(r);
    attrlen = len - sizeof(struct rtmsg);

    for (; RTA_OK(attr, attrlen); attr = RTA_NEXT(attr, attrlen)) {
        switch(attr->rta_type) {
            case RTA_DST:
                printf("Destination: %s(MISSING)\n", inet_ntoa(*(struct in_addr *)RTA_DATA(attr)));
                break;
            case RTA_GATEWAY:
                printf("Gateway: %s(MISSING)\n", inet_ntoa(*(struct in_addr *)RTA_DATA(attr)));
                break;
            case RTA_OIF:
                printf("Interface: %s(MISSING)\n", if_indextoname(*(int *)RTA_DATA(attr), buf));
                break;
        }
    }
}

int main1() {
    int sock;
    char buf[BUFSIZE];
    struct nlmsghdr *nlh;
    struct ifinfomsg *ifm;
    struct rtmsg *rtm;
    int len;

    sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (sock < 0) {
        perror("socket");
        exit(1);
    }

    memset(buf, 0, BUFSIZE);

    nlh = (struct nlmsghdr *)buf;
    nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
    nlh->nlmsg_type = RTM_GETROUTE;
    nlh->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
    nlh->nlmsg_seq = 1;
    nlh->nlmsg_pid = getpid();

    if (send(sock, nlh, nlh->nlmsg_len, 0) < 0) {
        perror("send");
        exit(1);
    }

    while (1) {
        len = recv(sock, buf, BUFSIZE, 0);
        if (len < 0) {
            perror("recv");
            exit(1);
        }

        for (nlh = (struct nlmsghdr *)buf; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) {
            switch(nlh->nlmsg_type) {
                case NLMSG_DONE:
                    printf("msg done");
                    return 0;
                case NLMSG_ERROR:
                    perror("NLMSG_ERROR");
                    exit(1);
                case RTM_NEWROUTE:
                    rtm = (struct rtmsg *)NLMSG_DATA(nlh);
                    if (rtm->rtm_family == AF_INET && rtm->rtm_table == RT_TABLE_MAIN && rtm->rtm_protocol == RTPROT_STATIC && rtm->rtm_type == RTN_UNICAST) 
                    {
                        printf("--------------------------------------------------\n");
                        process_route(rtm, buf, len);
                    }
                    break;
                default:
                    printf("message type: %d\r\n", nlh->nlmsg_type); 
                    break;
            }
        }
    }

    return 0;
}

int main()
{
    route_info_t route_info = {0};
    net_route_get("ens33", &route_info);
    printf("if_name: %s dst: %s gw: %s mask: %s metric: %d", route_info.if_name, route_info.dst_ip_addr_str, route_info.gateway_ip_addr_str, 
    route_info.mask_str, route_info.metric);
}